package cn.jw.starter.redis.core.api;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;

import com.alibaba.fastjson2.JSON;

import cn.hutool.extra.spring.SpringUtil;
import jodd.util.StringUtil;
import lombok.AllArgsConstructor;

/**
 * @author 王广帅
 * @version 1.0.0
 * @since 2025/6/24 21:59
 */
@AllArgsConstructor
public class RedisApiService {

    private StringRedisTemplate stringRedisTemplate;

    private String getKey(IRedisKeyGenerator redisKeyGenerator, String keyId) {
        JwRedisConfig redisConfig = SpringUtil.getBean(JwRedisConfig.class);
        return redisKeyGenerator.getKeyPrefix() + ":" + keyId + ":" + redisConfig.getKeyVersion();
    }

    public StringRedisTemplate getRedisTemplate() {
        return stringRedisTemplate;
    }

    /**
     * 向redis中存储对象值，如果是string类型，会直接存储，如果是object类型，会转化为json串存储
     *
     * @param keyGenerator
     * @param keyId
     * @param value
     */
    public void setValue(IRedisKeyGenerator keyGenerator, String keyId, Object value) {
        String key = this.getKey(keyGenerator, keyId);
        String msg;
        if (value instanceof String) {
            msg = (String)value;
        } else {
            msg = JSON.toJSONString(value);
        }
        if (keyGenerator.getExpireTime() != null) {
            stringRedisTemplate.opsForValue().set(key, msg);
        } else {
            stringRedisTemplate.opsForValue().set(key, msg, keyGenerator.getExpireTime());
        }
    }

    /**
     * 从redis中查询一个值
     *
     * @param keyGenerator
     * @param keyId
     * @return
     */
    public String getValue(IRedisKeyGenerator keyGenerator, String keyId) {
        String key = getKey(keyGenerator, keyId);
        String value = stringRedisTemplate.opsForValue().get(key);
        return value;
    }

    /**
     * 从redis中获取一个object的值
     *
     * @param keyGenerator
     * @param keyId
     * @param clzz
     * @param <T>
     * @return
     */
    public <T> T getValue(IRedisKeyGenerator keyGenerator, String keyId, Class<T> clzz) {
        String value = this.getValue(keyGenerator, keyId);
        if (StringUtil.isNotEmpty(value)) {
            return JSON.parseObject(value, clzz);
        }
        return null;
    }

    /**
     * 存储value，如果key已存在，返回false，不存储value，否则返回true
     *
     * @param keyGenerator
     * @param keyId
     * @param value
     * @return
     */
    public boolean setValueIfAbsent(IRedisKeyGenerator keyGenerator, String keyId, String value) {
        String key = this.getValue(keyGenerator, keyId);
        boolean result;
        if (keyGenerator.getExpireTime() != null) {
            result = stringRedisTemplate.opsForValue().setIfAbsent(key, value, keyGenerator.getExpireTime());
        } else {
            result = stringRedisTemplate.opsForValue().setIfAbsent(key, value);
        }
        return result;
    }

    public long hashIncr(IRedisKeyGenerator keyGenerator, String keyId, String hashKey, int delta) {
        String key = this.getKey(keyGenerator, keyId);
        Long result = stringRedisTemplate.opsForHash().increment(key, hashKey, delta);
        return result;
    }

    public String getHashValue(IRedisKeyGenerator redisKeyGenerator, String keyId, String hashKey) {
        String key = this.getKey(redisKeyGenerator, keyId);
        Object obj = stringRedisTemplate.opsForHash().get(key, hashKey);
        if (obj == null) {
            return null;
        }
        return (String)obj;
    }

    public void putHashValue(IRedisKeyGenerator keyGenerator, String keyId, String hashKey, Object obj) {
        String key = this.getKey(keyGenerator, keyId);
        String value = this.convertValue(obj);
        stringRedisTemplate.opsForHash().put(key, hashKey, value);
        if (keyGenerator.getExpireTime() != null) {
            stringRedisTemplate.expire(key, keyGenerator.getExpireTime());
        }
    }

    public void removeHashValue(IRedisKeyGenerator redisKeyGenerator, String keyId, String... hashKeys) {
        String key = this.getKey(redisKeyGenerator, keyId);
        stringRedisTemplate.opsForHash().delete(key, hashKeys);
    }

    /**
     * 从hash 中批量移除数据
     * 
     * @param redisKeyGenerator
     * @param keyId
     * @param hashKeys
     */
    public void removeHashValue(IRedisKeyGenerator redisKeyGenerator, String keyId, Collection<String> hashKeys) {
        String key = this.getKey(redisKeyGenerator, keyId);
        String[] array = new String[hashKeys.size()];
        Iterator<String> ite = hashKeys.iterator();
        for (int i = 0; i < hashKeys.size(); i++) {
            array[i] = ite.next();
        }
        HashOperations<String, String, String> opsForHash = stringRedisTemplate.opsForHash();
        opsForHash.delete(key, array);
    }

    public Map<String, String> getAllHashValue(IRedisKeyGenerator keyGenerator, String keyId,
        Collection<String> hashKeys) {
        String key = this.getKey(keyGenerator, keyId);
        HashOperations<String, String, String> hashOperations = stringRedisTemplate.opsForHash();
        List<String> values = hashOperations.multiGet(key, hashKeys);
        Map<String, String> resultMap = new HashMap<>(values.size());
        Iterator<String> ite = hashKeys.iterator();
        for (int i = 0; i < hashKeys.size(); i++) {
            if (i <= values.size() - 1) {
                String value = values.get(i);
                if (value != null) {
                    resultMap.put(ite.next(), value);
                }
            }
        }
        return resultMap;
    }

    public Map<String, String> getAllHashValue(IRedisKeyGenerator keyGenerator, String keyId) {
        String key = this.getKey(keyGenerator, keyId);
        Set<Object> keys = stringRedisTemplate.opsForHash().keys(key);
        List<String> strKeys = keys.stream().map(c -> (String)c).toList();
        return this.getAllHashValue(keyGenerator, keyId, strKeys);
    }

    /**
     * 给某个频道发送数据
     *
     * @param channel
     * @param message
     */
    public void convertAndSend(String channel, Object message) {
        stringRedisTemplate.convertAndSend(channel, message);
    }

    private String convertValue(Object obj) {
        String value;
        if (obj instanceof String) {
            value = (String)obj;
        } else {
            value = JSON.toJSONString(obj);
        }
        return value;
    }

    public void leftPush(IRedisKeyGenerator redisKeyGenerator, String keyId, Object obj) {
        String key = this.getKey(redisKeyGenerator, keyId);
        String value = convertValue(obj);
        stringRedisTemplate.opsForList().leftPush(key, value);
        if (redisKeyGenerator.getExpireTime() != null) {
            stringRedisTemplate.expire(key, redisKeyGenerator.getExpireTime());
        }
    }

    public void leftPushAll(IRedisKeyGenerator redisKeyGenerator, String keyId, Collection<String> list) {
        String key = this.getKey(redisKeyGenerator, keyId);
        stringRedisTemplate.opsForList().leftPushAll(key, list);
        if (redisKeyGenerator.getExpireTime() != null) {
            stringRedisTemplate.expire(key, redisKeyGenerator.getExpireTime());
        }
    }

    public void rightPush(IRedisKeyGenerator redisKeyGenerator, String keyId, Object obj) {
        String key = this.getKey(redisKeyGenerator, keyId);
        String value = this.convertValue(obj);
        stringRedisTemplate.opsForList().rightPush(key, value);
        if (redisKeyGenerator.getExpireTime() != null) {
            stringRedisTemplate.expire(key, redisKeyGenerator.getExpireTime());
        }
    }

    public void rightPushAll(IRedisKeyGenerator redisKeyGenerator, String keyId, Collection<String> list) {
        String key = this.getKey(redisKeyGenerator, keyId);
        stringRedisTemplate.opsForList().rightPushAll(key, list);
        if (redisKeyGenerator.getExpireTime() != null) {
            stringRedisTemplate.expire(key, redisKeyGenerator.getExpireTime());
        }
    }

    /**
     * 从左边获取并移除count个元素
     * 
     * @param redisKeyGenerator
     * @param keyId
     * @param count
     * @return
     */
    public List<String> getLeftListAll(IRedisKeyGenerator redisKeyGenerator, String keyId, long count) {
        String key = this.getKey(redisKeyGenerator, keyId);
        List<String> result = stringRedisTemplate.opsForList().leftPop(key, count);
        return result;
    }

    public void addSet(IRedisKeyGenerator redisKeyGenerator, String keyId, Object obj) {
        String key = this.getKey(redisKeyGenerator, keyId);
        String value = convertValue(obj);
        stringRedisTemplate.opsForSet().add(key, value);
        if (redisKeyGenerator.getExpireTime() != null) {
            stringRedisTemplate.expire(key, redisKeyGenerator.getExpireTime());
        }
    }

    public void addSetAll(IRedisKeyGenerator redisKeyGenerator, String keyId, Collection<String> objs) {
        String key = this.getKey(redisKeyGenerator, keyId);
        String[] array = new String[objs.size()];
        Iterator<String> ite = objs.iterator();
        for (int i = 0; i < objs.size(); i++) {
            array[i] = ite.next();
        }
        stringRedisTemplate.opsForSet().add(key, array);
        if (redisKeyGenerator.getExpireTime() != null) {
            stringRedisTemplate.expire(key, redisKeyGenerator.getExpireTime());
        }
    }

    public Collection<String> getSetAll(IRedisKeyGenerator redisKeyGenerator, String keyId) {
        String key = this.getKey(redisKeyGenerator, keyId);
        Set<String> members = stringRedisTemplate.opsForSet().members(key);
        return members;
    }

    public void removeFromSet(IRedisKeyGenerator redisKeyGenerator, String keyId, Object obj) {
        String key = this.getKey(redisKeyGenerator, keyId);
        String value = convertValue(obj);
        stringRedisTemplate.opsForSet().remove(key, value);
    }

}
